import React from "react";
import { CircularProgress, Snackbar } from "@material-ui/core";
import { Bi } from "@/module-00-codebase/pkg-01-container";
import { asyncWait, aw, pendingResolve } from "@/module-00-codebase/pkg-02-tool";
import { csses } from "@/module-00-codebase/pkg-00-const";
import { BaseElmt } from "@/module-00-codebase/pkg-03-abstract";
import { SnackbarProvider, useSnackbar } from "notistack";
const color = { color: csses.primaryColor };
const background = { backgroundColor: csses.primaryColor };
let loading_count = 0;
type MsgObj = { content: string; duration?: number; key?: any };
let messages: MsgObj[] = [];
let enableMulti = true;
export class MtLoading {
  public on(msg?: string, duration?: number) {
    const _loading_count = loading_count++;
    asyncWait(async () => {
      // has already had other loadings
      if (_loading_count === 0) cover = await Bi.cover.on();
      if (!!msg) messages.push({ content: msg, duration });
      if (!!msg || _loading_count === 0) {
        if (messages.length === 0) this.renderNoMessage();
        else if (enableMulti) /**/ await this.renderProvider();
        /*-----------------*/ else this.renderSnackBar();
      }
      if (typeof duration === "number") this.off(duration);
      Bi.log.debug(`loading_count_on: ${loading_count}, message=${msg}`);
    }, LOCK);
  }

  public off(duration?: number, remark?: string) {
    (async () => {
      if (typeof duration === "number") await aw(duration);
      await asyncWait(async () => {
        if (loading_count === 0) throw new Error("Loading has already been off.");
        if (--loading_count === 0) {
          await Bi.cover.off();
          prvdr = cover = (messages.length = 0) || null;
        }
        Bi.log.debug(`loading_count_off: ${loading_count}, message=${remark}`);
      }, LOCK);
    })();
  }
  private renderSnackBar() {
    Bi.renderer.render(<Snackbar open={true} message={messages[messages.length - 1]} className={Bi.styleRenderer.render(background)} />, getCover());
  }
  private renderNoMessage() {
    Bi.renderer.render(<CircularProgress className={Bi.styleRenderer.render(color)} />, getCover());
  }
  private async renderProvider() {
    const msg = messages.slice(-1)[0];
    await this.prepareSnackbarProvider();
    this.renderSnackbarProvider(msg);
  }
  private async prepareSnackbarProvider() {
    if (messages.length === 1) {
      const pendingRenderSnackBar = pendingResolve<ReturnType<typeof useSnackbar>>();
      const AsyncGetProvider = ({ children }: any) => (pendingRenderSnackBar.resolve(useSnackbar()) as any) || children || null;
      Bi.renderer.render(
        <SnackbarProvider maxSnack={10} anchorOrigin={{ vertical: "bottom", horizontal: "center" }} className={Bi.styleRenderer.render(background)}>
          <AsyncGetProvider />
        </SnackbarProvider>,
        getCover()
      );
      prvdr = await pendingRenderSnackBar;
    }
  }
  private renderSnackbarProvider(msg: MsgObj) {
    let opts: any;
    if (typeof msg.duration === "number") {
      opts = { autoHideDuration: msg.duration };
    } else {
      opts = { persist: true };
    }
    msg.key = getPrvdr().enqueueSnackbar(msg.content, opts);
  }
}
export const dependencies = () => ["Cover"];

// T2
const getCover = () => {
  if (!cover) throw new Error("No Cover for Loading");
  /*--*/ else return cover;
};
const getPrvdr = () => {
  if (!prvdr) throw new Error("No Provider for Loading");
  /*--*/ else return prvdr;
};
const LOCK = "Loading-Lock"; //Symbol();

// T3
let cover: BaseElmt<any> | null = null;
let prvdr: ReturnType<typeof useSnackbar> | null = null;
